﻿using System;
using System.Collections.Generic;
using System.Linq;
using Autodesk.Revit.DB;

namespace YJKStairs.CommonUnit
{
	public class CurveIntersection
	{
		public CurveIntersection(Element element, Curve curve)
		{
			this.m_element = element;
			this.m_curve = curve;
		}

		private List<Solid> GetGeometryInstanceSolid(GeometryInstance geoInstance)
		{
			List<Solid> list = new List<Solid>();
			foreach (GeometryObject geometryObject in geoInstance.GetInstanceGeometry())
			{
				if (geometryObject.GetType() == typeof(Solid))
				{
					Solid solid = geometryObject as Solid;
					if (null != solid)
					{
						list.Add(solid);
					}
				}
			}
			return list;
		}

		private List<Solid> GetElementAllSolid(Element element)
		{
			List<Solid> list = new List<Solid>();
			Options options = new Options();
			foreach (GeometryObject geometryObject in element.get_Geometry(options))
			{
				Type type = geometryObject.GetType();
				if (type == typeof(GeometryInstance))
				{
					GeometryInstance geoInstance = geometryObject as GeometryInstance;
					list.AddRange(this.GetGeometryInstanceSolid(geoInstance));
				}
				else if (type == typeof(Solid))
				{
					Solid solid = geometryObject as Solid;
					if (null != solid)
					{
						list.Add(solid);
					}
				}
			}
			return list;
		}

		private List<Face> GetStairsValidFaceOneSolid(Solid solid)
		{
			List<Face> list = new List<Face>();
			foreach (object obj in solid.Faces)
			{
				Face face = (Face)obj;
				XYZ xyz = face.ComputeNormal(UV.Zero);
				if (!xyz.Equals(XYZ.BasisX) && !xyz.Equals(XYZ.BasisY))
				{
					list.Add(face);
				}
			}
			return list;
		}

		private List<Face> GetStairsAllFace(Element element)
		{
			List<Face> list = new List<Face>();
			foreach (Solid solid in this.GetElementAllSolid(element))
			{
				list.AddRange(this.GetStairsValidFaceOneSolid(solid));
			}
			return list;
		}

		private void GetStairsResultArray(CurveIntersection.IntersectionType iType)
		{
			if (iType == CurveIntersection.IntersectionType.IT_SOLID)
			{
				foreach (Face face in this.GetStairsAllFace(this.m_element))
				{
					IntersectionResultArray intersectionResultArray = null;
					face.Intersect(this.m_curve, out intersectionResultArray);
					if (intersectionResultArray != null && !intersectionResultArray.IsEmpty)
					{
						this.m_InterResultArray.Add(intersectionResultArray);
					}
				}
			}
		}

		private void GetAllInterSectionPoint()
		{
			foreach (IntersectionResultArray intersectionResultArray in this.m_InterResultArray)
			{
				foreach (object obj in intersectionResultArray)
				{
					IntersectionResult intersectionResult = obj as IntersectionResult;
					if (intersectionResult != null)
					{
						XYZ xyzpoint = intersectionResult.XYZPoint;
						this.m_InterPoints.Add(xyzpoint);
					}
				}
			}
		}

		private List<XYZ> SortListPoint()
		{
			List<XYZ> list = new List<XYZ>();
			SortedList<double, List<XYZ>> sortedList = new SortedList<double, List<XYZ>>();
			foreach (XYZ xyz in this.m_InterPoints)
			{
				double z = xyz.Z;
				if (!sortedList.ContainsKey(z))
				{
					sortedList.Add(z, new List<XYZ>
					{
						xyz
					});
				}
				else
				{
					sortedList[z].Add(xyz);
				}
			}
			IEnumerator<KeyValuePair<double, List<XYZ>>> enumerator2 = sortedList.GetEnumerator();
			while (enumerator2.MoveNext())
			{
				List<XYZ> list2 = list;
				KeyValuePair<double, List<XYZ>> keyValuePair = enumerator2.Current;
				list2.AddRange(keyValuePair.Value);
			}
			list.Distinct<XYZ>();
			return list;
		}

		public List<XYZ> GetStairsRunLandSortedPoints(CurveIntersection.IntersectionType type = CurveIntersection.IntersectionType.IT_SOLID)
		{
			List<XYZ> result = null;
			if (type == CurveIntersection.IntersectionType.IT_SOLID)
			{
				this.GetStairsResultArray(type);
				this.GetAllInterSectionPoint();
				result = this.SortListPoint();
			}
			return result;
		}

		private Element m_element;

		private Curve m_curve;

		private List<XYZ> m_InterPoints = new List<XYZ>();

		private List<IntersectionResultArray> m_InterResultArray = new List<IntersectionResultArray>();

		public enum IntersectionType
		{
			IT_SOLID
		}
	}
}
